home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / temacd / xnview / XnView-beta1.exe / XnView / WebTemplate / Visuddhi - Lightbox / js / effects.js next >
Text File  |  2006-01-25  |  32KB  |  904 lines

  1. // Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
  2. // Contributors:
  3. //  Justin Palmer (http://encytemedia.com/)
  4. //  Mark Pilgrim (http://diveintomark.org/)
  5. //  Martin Bialasinki
  6. // 
  7. // See scriptaculous.js for full license.  
  8.  
  9. /* ------------- element ext -------------- */  
  10.  
  11. // converts rgb() and #xxx to #xxxxxx format,  
  12. // returns self (or first argument) if not convertable  
  13. String.prototype.parseColor = function() {  
  14.   var color = '#';  
  15.   if(this.slice(0,4) == 'rgb(') {  
  16.     var cols = this.slice(4,this.length-1).split(',');  
  17.     var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  18.   } else {  
  19.     if(this.slice(0,1) == '#') {  
  20.       if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
  21.       if(this.length==7) color = this.toLowerCase();  
  22.     }  
  23.   }  
  24.   return(color.length==7 ? color : (arguments[0] || this));  
  25. }
  26.  
  27. Element.collectTextNodes = function(element) {  
  28.   return $A($(element).childNodes).collect( function(node) {
  29.     return (node.nodeType==3 ? node.nodeValue : 
  30.       (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  31.   }).flatten().join('');
  32. }
  33.  
  34. Element.collectTextNodesIgnoreClass = function(element, className) {  
  35.   return $A($(element).childNodes).collect( function(node) {
  36.     return (node.nodeType==3 ? node.nodeValue : 
  37.       ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
  38.         Element.collectTextNodes(node) : ''));
  39.   }).flatten().join('');
  40. }
  41.  
  42. Element.setStyle = function(element, style) {
  43.   element = $(element);
  44.   for(k in style) element.style[k.camelize()] = style[k];
  45. }
  46.  
  47. Element.setContentZoom = function(element, percent) {  
  48.   Element.setStyle(element, {fontSize: (percent/100) + 'em'});   
  49.   if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);  
  50. }
  51.  
  52. Element.getOpacity = function(element){  
  53.   var opacity;
  54.   if (opacity = Element.getStyle(element, 'opacity'))  
  55.     return parseFloat(opacity);  
  56.   if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))  
  57.     if(opacity[1]) return parseFloat(opacity[1]) / 100;  
  58.   return 1.0;  
  59. }
  60.  
  61. Element.setOpacity = function(element, value){  
  62.   element= $(element);  
  63.   if (value == 1){
  64.     Element.setStyle(element, { opacity: 
  65.       (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 
  66.       0.999999 : null });
  67.     if(/MSIE/.test(navigator.userAgent))  
  68.       Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});  
  69.   } else {  
  70.     if(value < 0.00001) value = 0;  
  71.     Element.setStyle(element, {opacity: value});
  72.     if(/MSIE/.test(navigator.userAgent))  
  73.      Element.setStyle(element, 
  74.        { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
  75.                  'alpha(opacity='+value*100+')' });  
  76.   }   
  77. }  
  78.  
  79. Element.getInlineOpacity = function(element){  
  80.   return $(element).style.opacity || '';
  81. }  
  82.  
  83. Element.childrenWithClassName = function(element, className) {  
  84.   return $A($(element).getElementsByTagName('*')).select(
  85.     function(c) { return Element.hasClassName(c, className) });
  86. }
  87.  
  88. Array.prototype.call = function() {
  89.   var args = arguments;
  90.   this.each(function(f){ f.apply(this, args) });
  91. }
  92.  
  93. /*--------------------------------------------------------------------------*/
  94.  
  95. var Effect = {
  96.   tagifyText: function(element) {
  97.     var tagifyStyle = 'position:relative';
  98.     if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
  99.     element = $(element);
  100.     $A(element.childNodes).each( function(child) {
  101.       if(child.nodeType==3) {
  102.         child.nodeValue.toArray().each( function(character) {
  103.           element.insertBefore(
  104.             Builder.node('span',{style: tagifyStyle},
  105.               character == ' ' ? String.fromCharCode(160) : character), 
  106.               child);
  107.         });
  108.         Element.remove(child);
  109.       }
  110.     });
  111.   },
  112.   multiple: function(element, effect) {
  113.     var elements;
  114.     if(((typeof element == 'object') || 
  115.         (typeof element == 'function')) && 
  116.        (element.length))
  117.       elements = element;
  118.     else
  119.       elements = $(element).childNodes;
  120.       
  121.     var options = Object.extend({
  122.       speed: 0.1,
  123.       delay: 0.0
  124.     }, arguments[2] || {});
  125.     var masterDelay = options.delay;
  126.  
  127.     $A(elements).each( function(element, index) {
  128.       new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
  129.     });
  130.   },
  131.   PAIRS: {
  132.     'slide':  ['SlideDown','SlideUp'],
  133.     'blind':  ['BlindDown','BlindUp'],
  134.     'appear': ['Appear','Fade']
  135.   },
  136.   toggle: function(element, effect) {
  137.     element = $(element);
  138.     effect = (effect || 'appear').toLowerCase();
  139.     var options = Object.extend({
  140.       queue: { position:'end', scope:(element.id || 'global') }
  141.     }, arguments[2] || {});
  142.     Effect[Element.visible(element) ? 
  143.       Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
  144.   }
  145. };
  146.  
  147. var Effect2 = Effect; // deprecated
  148.  
  149. /* ------------- transitions ------------- */
  150.  
  151. Effect.Transitions = {}
  152.  
  153. Effect.Transitions.linear = function(pos) {
  154.   return pos;
  155. }
  156. Effect.Transitions.sinoidal = function(pos) {
  157.   return (-Math.cos(pos*Math.PI)/2) + 0.5;
  158. }
  159. Effect.Transitions.reverse  = function(pos) {
  160.   return 1-pos;
  161. }
  162. Effect.Transitions.flicker = function(pos) {
  163.   return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
  164. }
  165. Effect.Transitions.wobble = function(pos) {
  166.   return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  167. }
  168. Effect.Transitions.pulse = function(pos) {
  169.   return (Math.floor(pos*10) % 2 == 0 ? 
  170.     (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
  171. }
  172. Effect.Transitions.none = function(pos) {
  173.   return 0;
  174. }
  175. Effect.Transitions.full = function(pos) {
  176.   return 1;
  177. }
  178.  
  179. /* ------------- core effects ------------- */
  180.  
  181. Effect.ScopedQueue = Class.create();
  182. Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
  183.   initialize: function() {
  184.     this.effects  = [];
  185.     this.interval = null;
  186.   },
  187.   _each: function(iterator) {
  188.     this.effects._each(iterator);
  189.   },
  190.   add: function(effect) {
  191.     var timestamp = new Date().getTime();
  192.     
  193.     var position = (typeof effect.options.queue == 'string') ? 
  194.       effect.options.queue : effect.options.queue.position;
  195.     
  196.     switch(position) {
  197.       case 'front':
  198.         // move unstarted effects after this effect  
  199.         this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
  200.             e.startOn  += effect.finishOn;
  201.             e.finishOn += effect.finishOn;
  202.           });
  203.         break;
  204.       case 'end':
  205.         // start effect after last queued effect has finished
  206.         timestamp = this.effects.pluck('finishOn').max() || timestamp;
  207.         break;
  208.     }
  209.     
  210.     effect.startOn  += timestamp;
  211.     effect.finishOn += timestamp;
  212.     this.effects.push(effect);
  213.     if(!this.interval) 
  214.       this.interval = setInterval(this.loop.bind(this), 40);
  215.   },
  216.   remove: function(effect) {
  217.     this.effects = this.effects.reject(function(e) { return e==effect });
  218.     if(this.effects.length == 0) {
  219.       clearInterval(this.interval);
  220.       this.interval = null;
  221.     }
  222.   },
  223.   loop: function() {
  224.     var timePos = new Date().getTime();
  225.     this.effects.invoke('loop', timePos);
  226.   }
  227. });
  228.  
  229. Effect.Queues = {
  230.   instances: $H(),
  231.   get: function(queueName) {
  232.     if(typeof queueName != 'string') return queueName;
  233.     
  234.     if(!this.instances[queueName])
  235.       this.instances[queueName] = new Effect.ScopedQueue();
  236.       
  237.     return this.instances[queueName];
  238.   }
  239. }
  240. Effect.Queue = Effect.Queues.get('global');
  241.  
  242. Effect.DefaultOptions = {
  243.   transition: Effect.Transitions.sinoidal,
  244.   duration:   1.0,   // seconds
  245.   fps:        25.0,  // max. 25fps due to Effect.Queue implementation
  246.   sync:       false, // true for combining
  247.   from:       0.0,
  248.   to:         1.0,
  249.   delay:      0.0,
  250.   queue:      'parallel'
  251. }
  252.  
  253. Effect.Base = function() {};
  254. Effect.Base.prototype = {
  255.   position: null,
  256.   start: function(options) {
  257.     this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
  258.     this.currentFrame = 0;
  259.     this.state        = 'idle';
  260.     this.startOn      = this.options.delay*1000;
  261.     this.finishOn     = this.startOn + (this.options.duration*1000);
  262.     this.event('beforeStart');
  263.     if(!this.options.sync)
  264.       Effect.Queues.get(typeof this.options.queue == 'string' ? 
  265.         'global' : this.options.queue.scope).add(this);
  266.   },
  267.   loop: function(timePos) {
  268.     if(timePos >= this.startOn) {
  269.       if(timePos >= this.finishOn) {
  270.         this.render(1.0);
  271.         this.cancel();
  272.         this.event('beforeFinish');
  273.         if(this.finish) this.finish(); 
  274.         this.event('afterFinish');
  275.         return;  
  276.       }
  277.       var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
  278.       var frame = Math.round(pos * this.options.fps * this.options.duration);
  279.       if(frame > this.currentFrame) {
  280.         this.render(pos);
  281.         this.currentFrame = frame;
  282.       }
  283.     }
  284.   },
  285.   render: function(pos) {
  286.     if(this.state == 'idle') {
  287.       this.state = 'running';
  288.       this.event('beforeSetup');
  289.       if(this.setup) this.setup();
  290.       this.event('afterSetup');
  291.     }
  292.     if(this.state == 'running') {
  293.       if(this.options.transition) pos = this.options.transition(pos);
  294.       pos *= (this.options.to-this.options.from);
  295.       pos += this.options.from;
  296.       this.position = pos;
  297.       this.event('beforeUpdate');
  298.       if(this.update) this.update(pos);
  299.       this.event('afterUpdate');
  300.     }
  301.   },
  302.   cancel: function() {
  303.     if(!this.options.sync)
  304.       Effect.Queues.get(typeof this.options.queue == 'string' ? 
  305.         'global' : this.options.queue.scope).remove(this);
  306.     this.state = 'finished';
  307.   },
  308.   event: function(eventName) {
  309.     if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
  310.     if(this.options[eventName]) this.options[eventName](this);
  311.   },
  312.   inspect: function() {
  313.     return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
  314.   }
  315. }
  316.  
  317. Effect.Parallel = Class.create();
  318. Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  319.   initialize: function(effects) {
  320.     this.effects = effects || [];
  321.     this.start(arguments[1]);
  322.   },
  323.   update: function(position) {
  324.     this.effects.invoke('render', position);
  325.   },
  326.   finish: function(position) {
  327.     this.effects.each( function(effect) {
  328.       effect.render(1.0);
  329.       effect.cancel();
  330.       effect.event('beforeFinish');
  331.       if(effect.finish) effect.finish(position);
  332.       effect.event('afterFinish');
  333.     });
  334.   }
  335. });
  336.  
  337. Effect.Opacity = Class.create();
  338. Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  339.   initialize: function(element) {
  340.     this.element = $(element);
  341.     // make this work on IE on elements without 'layout'
  342.     if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
  343.       Element.setStyle(this.element, {zoom: 1});
  344.     var options = Object.extend({
  345.       from: Element.getOpacity(this.element) || 0.0,
  346.       to:   1.0
  347.     }, arguments[1] || {});
  348.     this.start(options);
  349.   },
  350.   update: function(position) {
  351.     Element.setOpacity(this.element, position);
  352.   }
  353. });
  354.  
  355. Effect.Move = Class.create();
  356. Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
  357.   initialize: function(element) {
  358.     this.element = $(element);
  359.     var options = Object.extend({
  360.       x:    0,
  361.       y:    0,
  362.       mode: 'relative'
  363.     }, arguments[1] || {});
  364.     this.start(options);
  365.   },
  366.   setup: function() {
  367.     // Bug in Opera: Opera returns the "real" position of a static element or
  368.     // relative element that does not have top/left explicitly set.
  369.     // ==> Always set top and left for position relative elements in your stylesheets 
  370.     // (to 0 if you do not need them) 
  371.     Element.makePositioned(this.element);
  372.     this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
  373.     this.originalTop  = parseFloat(Element.getStyle(this.element,'top')  || '0');
  374.     if(this.options.mode == 'absolute') {
  375.       // absolute movement, so we need to calc deltaX and deltaY
  376.       this.options.x = this.options.x - this.originalLeft;
  377.       this.options.y = this.options.y - this.originalTop;
  378.     }
  379.   },
  380.   update: function(position) {
  381.     Element.setStyle(this.element, {
  382.       left: this.options.x  * position + this.originalLeft + 'px',
  383.       top:  this.options.y  * position + this.originalTop  + 'px'
  384.     });
  385.   }
  386. });
  387.  
  388. // for backwards compatibility
  389. Effect.MoveBy = function(element, toTop, toLeft) {
  390.   return new Effect.Move(element, 
  391.     Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
  392. };
  393.  
  394. Effect.Scale = Class.create();
  395. Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
  396.   initialize: function(element, percent) {
  397.     this.element = $(element)
  398.     var options = Object.extend({
  399.       scaleX: true,
  400.       scaleY: true,
  401.       scaleContent: true,
  402.       scaleFromCenter: false,
  403.       scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
  404.       scaleFrom: 100.0,
  405.       scaleTo:   percent
  406.     }, arguments[2] || {});
  407.     this.start(options);
  408.   },
  409.   setup: function() {
  410.     this.restoreAfterFinish = this.options.restoreAfterFinish || false;
  411.     this.elementPositioning = Element.getStyle(this.element,'position');
  412.     
  413.     this.originalStyle = {};
  414.     ['top','left','width','height','fontSize'].each( function(k) {
  415.       this.originalStyle[k] = this.element.style[k];
  416.     }.bind(this));
  417.       
  418.     this.originalTop  = this.element.offsetTop;
  419.     this.originalLeft = this.element.offsetLeft;
  420.     
  421.     var fontSize = Element.getStyle(this.element,'font-size') || '100%';
  422.     ['em','px','%'].each( function(fontSizeType) {
  423.       if(fontSize.indexOf(fontSizeType)>0) {
  424.         this.fontSize     = parseFloat(fontSize);
  425.         this.fontSizeType = fontSizeType;
  426.       }
  427.     }.bind(this));
  428.     
  429.     this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
  430.     
  431.     this.dims = null;
  432.     if(this.options.scaleMode=='box')
  433.       this.dims = [this.element.offsetHeight, this.element.offsetWidth];
  434.     if(/^content/.test(this.options.scaleMode))
  435.       this.dims = [this.element.scrollHeight, this.element.scrollWidth];
  436.     if(!this.dims)
  437.       this.dims = [this.options.scaleMode.originalHeight,
  438.                    this.options.scaleMode.originalWidth];
  439.   },
  440.   update: function(position) {
  441.     var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
  442.     if(this.options.scaleContent && this.fontSize)
  443.       Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
  444.     this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  445.   },
  446.   finish: function(position) {
  447.     if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
  448.   },
  449.   setDimensions: function(height, width) {
  450.     var d = {};
  451.     if(this.options.scaleX) d.width = width + 'px';
  452.     if(this.options.scaleY) d.height = height + 'px';
  453.     if(this.options.scaleFromCenter) {
  454.       var topd  = (height - this.dims[0])/2;
  455.       var leftd = (width  - this.dims[1])/2;
  456.       if(this.elementPositioning == 'absolute') {
  457.         if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
  458.         if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
  459.       } else {
  460.         if(this.options.scaleY) d.top = -topd + 'px';
  461.         if(this.options.scaleX) d.left = -leftd + 'px';
  462.       }
  463.     }
  464.     Element.setStyle(this.element, d);
  465.   }
  466. });
  467.  
  468. Effect.Highlight = Class.create();
  469. Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
  470.   initialize: function(element) {
  471.     this.element = $(element);
  472.     var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
  473.     this.start(options);
  474.   },
  475.   setup: function() {
  476.     // Prevent executing on elements not in the layout flow
  477.     if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
  478.     // Disable background image during the effect
  479.     this.oldStyle = {
  480.       backgroundImage: Element.getStyle(this.element, 'background-image') };
  481.     Element.setStyle(this.element, {backgroundImage: 'none'});
  482.     if(!this.options.endcolor)
  483.       this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
  484.     if(!this.options.restorecolor)
  485.       this.options.restorecolor = Element.getStyle(this.element, 'background-color');
  486.     // init color calculations
  487.     this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
  488.     this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  489.   },
  490.   update: function(position) {
  491.     Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
  492.       return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
  493.   },
  494.   finish: function() {
  495.     Element.setStyle(this.element, Object.extend(this.oldStyle, {
  496.       backgroundColor: this.options.restorecolor
  497.     }));
  498.   }
  499. });
  500.  
  501. Effect.ScrollTo = Class.create();
  502. Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
  503.   initialize: function(element) {
  504.     this.element = $(element);
  505.     this.start(arguments[1] || {});
  506.   },
  507.   setup: function() {
  508.     Position.prepare();
  509.     var offsets = Position.cumulativeOffset(this.element);
  510.     if(this.options.offset) offsets[1] += this.options.offset;
  511.     var max = window.innerHeight ? 
  512.       window.height - window.innerHeight :
  513.       document.body.scrollHeight - 
  514.         (document.documentElement.clientHeight ? 
  515.           document.documentElement.clientHeight : document.body.clientHeight);
  516.     this.scrollStart = Position.deltaY;
  517.     this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
  518.   },
  519.   update: function(position) {
  520.     Position.prepare();
  521.     window.scrollTo(Position.deltaX, 
  522.       this.scrollStart + (position*this.delta));
  523.   }
  524. });
  525.  
  526. /* ------------- combination effects ------------- */
  527.  
  528. Effect.Fade = function(element) {
  529.   var oldOpacity = Element.getInlineOpacity(element);
  530.   var options = Object.extend({
  531.   from: Element.getOpacity(element) || 1.0,
  532.   to:   0.0,
  533.   afterFinishInternal: function(effect) { with(Element) { 
  534.     if(effect.options.to!=0) return;
  535.     hide(effect.element);
  536.     setStyle(effect.element, {opacity: oldOpacity}); }}
  537.   }, arguments[1] || {});
  538.   return new Effect.Opacity(element,options);
  539. }
  540.  
  541. Effect.Appear = function(element) {
  542.   var options = Object.extend({
  543.   from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
  544.   to:   1.0,
  545.   beforeSetup: function(effect) { with(Element) {
  546.     setOpacity(effect.element, effect.options.from);
  547.     show(effect.element); }}
  548.   }, arguments[1] || {});
  549.   return new Effect.Opacity(element,options);
  550. }
  551.  
  552. Effect.Puff = function(element) {
  553.   element = $(element);
  554.   var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
  555.   return new Effect.Parallel(
  556.    [ new Effect.Scale(element, 200, 
  557.       { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
  558.      new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
  559.      Object.extend({ duration: 1.0, 
  560.       beforeSetupInternal: function(effect) { with(Element) {
  561.         setStyle(effect.effects[0].element, {position: 'absolute'}); }},
  562.       afterFinishInternal: function(effect) { with(Element) {
  563.          hide(effect.effects[0].element);
  564.          setStyle(effect.effects[0].element, oldStyle); }}
  565.      }, arguments[1] || {})
  566.    );
  567. }
  568.  
  569. Effect.BlindUp = function(element) {
  570.   element = $(element);
  571.   Element.makeClipping(element);
  572.   return new Effect.Scale(element, 0, 
  573.     Object.extend({ scaleContent: false, 
  574.       scaleX: false, 
  575.       restoreAfterFinish: true,
  576.       afterFinishInternal: function(effect) { with(Element) {
  577.         [hide, undoClipping].call(effect.element); }} 
  578.     }, arguments[1] || {})
  579.   );
  580. }
  581.  
  582. Effect.BlindDown = function(element) {
  583.   element = $(element);
  584.   var oldHeight = Element.getStyle(element, 'height');
  585.   var elementDimensions = Element.getDimensions(element);
  586.   return new Effect.Scale(element, 100, 
  587.     Object.extend({ scaleContent: false, 
  588.       scaleX: false,
  589.       scaleFrom: 0,
  590.       scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  591.       restoreAfterFinish: true,
  592.       afterSetup: function(effect) { with(Element) {
  593.         makeClipping(effect.element);
  594.         setStyle(effect.element, {height: '0px'});
  595.         show(effect.element); 
  596.       }},  
  597.       afterFinishInternal: function(effect) { with(Element) {
  598.         undoClipping(effect.element);
  599.         setStyle(effect.element, {height: oldHeight});
  600.       }}
  601.     }, arguments[1] || {})
  602.   );
  603. }
  604.  
  605. Effect.SwitchOff = function(element) {
  606.   element = $(element);
  607.   var oldOpacity = Element.getInlineOpacity(element);
  608.   return new Effect.Appear(element, { 
  609.     duration: 0.4,
  610.     from: 0,
  611.     transition: Effect.Transitions.flicker,
  612.     afterFinishInternal: function(effect) {
  613.       new Effect.Scale(effect.element, 1, { 
  614.         duration: 0.3, scaleFromCenter: true,
  615.         scaleX: false, scaleContent: false, restoreAfterFinish: true,
  616.         beforeSetup: function(effect) { with(Element) {
  617.           [makePositioned,makeClipping].call(effect.element);
  618.         }},
  619.         afterFinishInternal: function(effect) { with(Element) {
  620.           [hide,undoClipping,undoPositioned].call(effect.element);
  621.           setStyle(effect.element, {opacity: oldOpacity});
  622.         }}
  623.       })
  624.     }
  625.   });
  626. }
  627.  
  628. Effect.DropOut = function(element) {
  629.   element = $(element);
  630.   var oldStyle = {
  631.     top: Element.getStyle(element, 'top'),
  632.     left: Element.getStyle(element, 'left'),
  633.     opacity: Element.getInlineOpacity(element) };
  634.   return new Effect.Parallel(
  635.     [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
  636.       new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
  637.     Object.extend(
  638.       { duration: 0.5,
  639.         beforeSetup: function(effect) { with(Element) {
  640.           makePositioned(effect.effects[0].element); }},
  641.         afterFinishInternal: function(effect) { with(Element) {
  642.           [hide, undoPositioned].call(effect.effects[0].element);
  643.           setStyle(effect.effects[0].element, oldStyle); }} 
  644.       }, arguments[1] || {}));
  645. }
  646.  
  647. Effect.Shake = function(element) {
  648.   element = $(element);
  649.   var oldStyle = {
  650.     top: Element.getStyle(element, 'top'),
  651.     left: Element.getStyle(element, 'left') };
  652.       return new Effect.Move(element, 
  653.         { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
  654.       new Effect.Move(effect.element,
  655.         { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  656.       new Effect.Move(effect.element,
  657.         { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  658.       new Effect.Move(effect.element,
  659.         { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  660.       new Effect.Move(effect.element,
  661.         { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
  662.       new Effect.Move(effect.element,
  663.         { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
  664.         undoPositioned(effect.element);
  665.         setStyle(effect.element, oldStyle);
  666.   }}}) }}) }}) }}) }}) }});
  667. }
  668.  
  669. Effect.SlideDown = function(element) {
  670.   element = $(element);
  671.   Element.cleanWhitespace(element);
  672.   // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  673.   var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
  674.   var elementDimensions = Element.getDimensions(element);
  675.   return new Effect.Scale(element, 100, Object.extend({ 
  676.     scaleContent: false, 
  677.     scaleX: false, 
  678.     scaleFrom: 0,
  679.     scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
  680.     restoreAfterFinish: true,
  681.     afterSetup: function(effect) { with(Element) {
  682.       makePositioned(effect.element);
  683.       makePositioned(effect.element.firstChild);
  684.       if(window.opera) setStyle(effect.element, {top: ''});
  685.       makeClipping(effect.element);
  686.       setStyle(effect.element, {height: '0px'});
  687.       show(element); }},
  688.     afterUpdateInternal: function(effect) { with(Element) {
  689.       setStyle(effect.element.firstChild, {bottom:
  690.         (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
  691.     afterFinishInternal: function(effect) { with(Element) {
  692.       undoClipping(effect.element); 
  693.       undoPositioned(effect.element.firstChild);
  694.       undoPositioned(effect.element);
  695.       setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
  696.     }, arguments[1] || {})
  697.   );
  698. }
  699.   
  700. Effect.SlideUp = function(element) {
  701.   element = $(element);
  702.   Element.cleanWhitespace(element);
  703.   var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
  704.   return new Effect.Scale(element, 0, 
  705.    Object.extend({ scaleContent: false, 
  706.     scaleX: false, 
  707.     scaleMode: 'box',
  708.     scaleFrom: 100,
  709.     restoreAfterFinish: true,
  710.     beforeStartInternal: function(effect) { with(Element) {
  711.       makePositioned(effect.element);
  712.       makePositioned(effect.element.firstChild);
  713.       if(window.opera) setStyle(effect.element, {top: ''});
  714.       makeClipping(effect.element);
  715.       show(element); }},  
  716.     afterUpdateInternal: function(effect) { with(Element) {
  717.       setStyle(effect.element.firstChild, {bottom:
  718.         (effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
  719.     afterFinishInternal: function(effect) { with(Element) {
  720.         [hide, undoClipping].call(effect.element); 
  721.         undoPositioned(effect.element.firstChild);
  722.         undoPositioned(effect.element);
  723.         setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
  724.    }, arguments[1] || {})
  725.   );
  726. }
  727.  
  728. // Bug in opera makes the TD containing this element expand for a instance after finish 
  729. Effect.Squish = function(element) {
  730.   return new Effect.Scale(element, window.opera ? 1 : 0, 
  731.     { restoreAfterFinish: true,
  732.       beforeSetup: function(effect) { with(Element) {
  733.         makeClipping(effect.element); }},  
  734.       afterFinishInternal: function(effect) { with(Element) {
  735.         hide(effect.element); 
  736.         undoClipping(effect.element); }}
  737.   });
  738. }
  739.  
  740. Effect.Grow = function(element) {
  741.   element = $(element);
  742.   var options = Object.extend({
  743.     direction: 'center',
  744.     moveTransistion: Effect.Transitions.sinoidal,
  745.     scaleTransition: Effect.Transitions.sinoidal,
  746.     opacityTransition: Effect.Transitions.full
  747.   }, arguments[1] || {});
  748.   var oldStyle = {
  749.     top: element.style.top,
  750.     left: element.style.left,
  751.     height: element.style.height,
  752.     width: element.style.width,
  753.     opacity: Element.getInlineOpacity(element) };
  754.  
  755.   var dims = Element.getDimensions(element);    
  756.   var initialMoveX, initialMoveY;
  757.   var moveX, moveY;
  758.   
  759.   switch (options.direction) {
  760.     case 'top-left':
  761.       initialMoveX = initialMoveY = moveX = moveY = 0; 
  762.       break;
  763.     case 'top-right':
  764.       initialMoveX = dims.width;
  765.       initialMoveY = moveY = 0;
  766.       moveX = -dims.width;
  767.       break;
  768.     case 'bottom-left':
  769.       initialMoveX = moveX = 0;
  770.       initialMoveY = dims.height;
  771.       moveY = -dims.height;
  772.       break;
  773.     case 'bottom-right':
  774.       initialMoveX = dims.width;
  775.       initialMoveY = dims.height;
  776.       moveX = -dims.width;
  777.       moveY = -dims.height;
  778.       break;
  779.     case 'center':
  780.       initialMoveX = dims.width / 2;
  781.       initialMoveY = dims.height / 2;
  782.       moveX = -dims.width / 2;
  783.       moveY = -dims.height / 2;
  784.       break;
  785.   }
  786.   
  787.   return new Effect.Move(element, {
  788.     x: initialMoveX,
  789.     y: initialMoveY,
  790.     duration: 0.01, 
  791.     beforeSetup: function(effect) { with(Element) {
  792.       hide(effect.element);
  793.       makeClipping(effect.element);
  794.       makePositioned(effect.element);
  795.     }},
  796.     afterFinishInternal: function(effect) {
  797.       new Effect.Parallel(
  798.         [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
  799.           new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
  800.           new Effect.Scale(effect.element, 100, {
  801.             scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
  802.             sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
  803.         ], Object.extend({
  804.              beforeSetup: function(effect) { with(Element) {
  805.                setStyle(effect.effects[0].element, {height: '0px'});
  806.                show(effect.effects[0].element); }},
  807.              afterFinishInternal: function(effect) { with(Element) {
  808.                [undoClipping, undoPositioned].call(effect.effects[0].element); 
  809.                setStyle(effect.effects[0].element, oldStyle); }}
  810.            }, options)
  811.       )
  812.     }
  813.   });
  814. }
  815.  
  816. Effect.Shrink = function(element) {
  817.   element = $(element);
  818.   var options = Object.extend({
  819.     direction: 'center',
  820.     moveTransistion: Effect.Transitions.sinoidal,
  821.     scaleTransition: Effect.Transitions.sinoidal,
  822.     opacityTransition: Effect.Transitions.none
  823.   }, arguments[1] || {});
  824.   var oldStyle = {
  825.     top: element.style.top,
  826.     left: element.style.left,
  827.     height: element.style.height,
  828.     width: element.style.width,
  829.     opacity: Element.getInlineOpacity(element) };
  830.  
  831.   var dims = Element.getDimensions(element);
  832.   var moveX, moveY;
  833.   
  834.   switch (options.direction) {
  835.     case 'top-left':
  836.       moveX = moveY = 0;
  837.       break;
  838.     case 'top-right':
  839.       moveX = dims.width;
  840.       moveY = 0;
  841.       break;
  842.     case 'bottom-left':
  843.       moveX = 0;
  844.       moveY = dims.height;
  845.       break;
  846.     case 'bottom-right':
  847.       moveX = dims.width;
  848.       moveY = dims.height;
  849.       break;
  850.     case 'center':  
  851.       moveX = dims.width / 2;
  852.       moveY = dims.height / 2;
  853.       break;
  854.   }
  855.   
  856.   return new Effect.Parallel(
  857.     [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
  858.       new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
  859.       new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
  860.     ], Object.extend({            
  861.          beforeStartInternal: function(effect) { with(Element) {
  862.            [makePositioned, makeClipping].call(effect.effects[0].element) }},
  863.          afterFinishInternal: function(effect) { with(Element) {
  864.            [hide, undoClipping, undoPositioned].call(effect.effects[0].element);
  865.            setStyle(effect.effects[0].element, oldStyle); }}
  866.        }, options)
  867.   );
  868. }
  869.  
  870. Effect.Pulsate = function(element) {
  871.   element = $(element);
  872.   var options    = arguments[1] || {};
  873.   var oldOpacity = Element.getInlineOpacity(element);
  874.   var transition = options.transition || Effect.Transitions.sinoidal;
  875.   var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
  876.   reverser.bind(transition);
  877.   return new Effect.Opacity(element, 
  878.     Object.extend(Object.extend({  duration: 3.0, from: 0,
  879.       afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
  880.     }, options), {transition: reverser}));
  881. }
  882.  
  883. Effect.Fold = function(element) {
  884.   element = $(element);
  885.   var oldStyle = {
  886.     top: element.style.top,
  887.     left: element.style.left,
  888.     width: element.style.width,
  889.     height: element.style.height };
  890.   Element.makeClipping(element);
  891.   return new Effect.Scale(element, 5, Object.extend({   
  892.     scaleContent: false,
  893.     scaleX: false,
  894.     afterFinishInternal: function(effect) {
  895.     new Effect.Scale(element, 1, { 
  896.       scaleContent: false, 
  897.       scaleY: false,
  898.       afterFinishInternal: function(effect) { with(Element) {
  899.         [hide, undoClipping].call(effect.element); 
  900.         setStyle(effect.element, oldStyle);
  901.       }} });
  902.   }}, arguments[1] || {}));
  903. }
  904.